#pragma once

#include <iostream>
#include <string>
#include <unordered_map>
#include <cstring>
#include <cerrno>
#include <cassert>
#include <signal.h>
#include <unistd.h>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <pthread.h>
#include <ctype.h>
#include "ThreadPool/log.hpp"
#include "ThreadPool/threadPool.hpp"
#include "ThreadPool/task.hpp"

static void service(int sock,const std::string& client_ip,uint16_t& client_port,
                    const std::string& thread_name)
{   
    char buffer[1024];
    while(true)
    {
        ssize_t s = read(sock,buffer,sizeof(buffer)-1);
        if(s > 0)
        {
            buffer[s] = 0;
            std::cout << thread_name << "|" << client_ip << "-" << client_port << "# " << buffer << std::endl;
        }
        else if(s == 0)//对端关闭连接
        {
            logMessage(NORMAL, "%s:%d shutdown, me too!", client_ip.c_str(), client_port);
            break;
        }
        else
        {
            logMessage(ERROR, "read socket error, %d:%s", errno, strerror(errno));
            break;
        }

        write(sock,buffer,strlen(buffer));
    }
    close(sock);
}

class TcpServer
{
private:
    uint16_t _port;
    std::string _ip;
    int _listenSock;
    const int backlog = 20;
    std::unique_ptr<ThreadPool<Task>> _threadpool_ptr;
    // static void* threadRoutine(void* args)
    // {
    //     pthread_detach(pthread_self());
    //     ThreadData* td = (ThreadData*)args;
    //     service(td->_sock,td->_ip,td->_port);
    //     delete td;

    //     return nullptr;
    // }
public:
    TcpServer(uint16_t port, std::string ip = "0.0.0.0")
    :_port(port),_ip(ip),_listenSock(-1)
    ,_threadpool_ptr(ThreadPool<Task>::getThreadPool())
    {  }

    void initServer()
    {
        //1.创建套接字
        _listenSock = socket(AF_INET,SOCK_STREAM,0);
        if(_listenSock < 0)
        {
            logMessage(FATAL,"create socket error %d:%s",errno,strerror(errno));
            exit(1);
        }
        logMessage(NORMAL, "create socket success, listensock: %d", _listenSock); // 3

        //2.bind
        struct sockaddr_in local;
        bzero(&local,0);
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());

        if(bind(_listenSock,(struct sockaddr*)&local,sizeof(local)) < 0)
        {
            logMessage(FATAL,"bind error %d:%s",errno,strerror(errno));
            exit(1);
        }

        //3.监听
        if(listen(_listenSock,backlog) < 0)
        {
            logMessage(FATAL,"listen error %d:%s",errno,strerror(errno));
            exit(1);
        }

       logMessage(NORMAL, "init server success");
    }

    void start()
    {   
        //signal(SIGCHLD, SIG_IGN); // 对SIGCHLD，主动忽略SIGCHLD信号，子进程退出的时候，会自动释放自己的僵尸状态
        _threadpool_ptr->run();
        while(true)
        {
            //4.获取连接
            struct sockaddr_in src;
            socklen_t len = sizeof(src);
            int serSocket = accept(_listenSock,(struct sockaddr*)&src,&len);
            if(serSocket < 0)
            {
                logMessage(ERROR,"accept error %d:%s",errno,strerror(errno));
                continue;
            }

            uint16_t client_port = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);
            logMessage(NORMAL,"link success, serSocket: %d, client_port : %d, client_ip: %s",serSocket,client_port,client_ip.c_str());

            // verison4 --- 线程池版本
            Task t(serSocket, client_ip, client_port, service);
            _threadpool_ptr->pushTask(t);

            // // version 3 --- 多线程版本
            // ThreadData* td = new ThreadData(1,serSocket,client_ip,client_port);
            // Thread thread(threadRoutine,td);
            // thread.start();
            // //thread.join();
            // close(serSocket);

            // version 1 -- 单进程循环版 -- 只能够进行一次处理一个客户端，处理完了一个，才能处理下一个
            // 很显然，是不能够直接被使用的！ -- 为什么？ 单进程
            //service(serSocket, client_ip, client_port);
            // close(serSocket);

            // version 2.0 -- 多进程版 --- 创建子进程
            // 让子进程给新的连接提供服务，子进程能不能打开父进程曾经打开的文件fd呢？能
            // pid_t id = fork();
            // assert(id != -1);
            // if(id == 0)
            // {
            //     close(_listenSock);//关闭子进程不需要的文件描述符
            //     service(serSocket, client_ip, client_port);
            //     exit(0);
            // }

            // close(serSocket);//关闭父进程不需要的文件描述符

            // version2.1 -- 多进程版
            // pid_t id = fork();
            // assert(id != -1);
            // if(id == 0)
            // {
            //     close(_listenSock);
            //     if(fork() > 0) exit(0);
            //     service(serSocket, client_ip, client_port);
            //     exit(0);
            // }
            // waitpid(id,nullptr,0);

            // close(serSocket);
        }
    }

    ~TcpServer()
    {}
};



